#include <buola/widgets/cmenubar.h>

#include <buola/app/ctimer.h>
#include <buola/image/cimage.h>
#include <buola/gui/cimagematrix.h>
#include <buola/gui/cicon.h>
#include <buola/image/cfont.h>
#include <buola/gui/cmenu.h>
#include <buola/gui/ctoolkit.h>
#include <buola/image/cgc.h>

#include <buola/widgets/ctheme.h>

namespace buola { namespace gui {

CMenuBar::CMenuBar(PMenu pMenu)
    :   mMenu(pMenu)
{
    mIconSize=CIcon::SMALLEST;
    mSelected=-1;
    mOpenSubMenu=-1;
    mPressed=false;

    mTimer=new CTimer(chrono::milliseconds(300));
    mTimer->sTimer.Connect(&CMenuBar::OnTimer,this);

    mFont=img::CFont::GetStock(L"menubold");
    mBoldFont=img::CFont::GetStock(L"menubold");

    get_default_theme()->PrepareMenuBar(this);

    ShapeAll();
    PosAll();
}

CMenuBar::~CMenuBar()
{
    if(mOpenSubMenu>=0)
        mSubMenu->Unmap();
    delete mTimer;
}

PMenuItem CMenuBar::GetSelected()
{
    if(mSelected==-1) return nullptr;
    return mMenu->Get(mSelected);
}

void CMenuBar::SetIconSize(int pSize)
{
    mIconSize=pSize;

    ShapeAll();
    PosAll();
}

void CMenuBar::ShapeAll()
{
    CSize_i lIconSize(mIconSize,mIconSize);
    mItemSize.resize(mMenu->size());

    if(GetStyle(STYLE_POPUP))
    {
        bool lIcons=false;

        for(int i=0;i<mMenu->size();i++)
        {
            if(mMenu->Get(i)->GetIcon()) lIcons=true;
        }

        for(int i=0;i<mMenu->size();i++)
        {
            PMenuItem lItem=mMenu->Get(i);

            if(lItem->IsSeparator())
            {
                mItemSize[i]={60,5};
            }
            else
            {
                mItemSize[i].x=(int)mFont->GetWidth(lItem->GetText())+8;
                mItemSize[i].y=(int)mFont->GetHeight()+4;

                if(lIcons)
                {
                    mItemSize[i].x+=lIconSize.x;
                    mItemSize[i].y=max(mItemSize[i].y,lIconSize.y+4.0);
                }
                if(lItem->IsSubMenu())
                    mItemSize[i].x+=12;
            }
        }
    }
    else
    {
        for(int i=0;i<mMenu->size();i++)
        {
            PMenuItem lItem=mMenu->Get(i);

            if(lItem->IsSeparator())
            {
                mItemSize[i]={5,Size().y};
            }
            else
            {
                mItemSize[i]={mFont->GetWidth(lItem->GetText())+10,Size().y};
            }
        }
    }
}

void CMenuBar::PosAll()
{
    CSize_d lIconSize(mIconSize,mIconSize);
    mItemPos.resize(mMenu->size());

    if(GetStyle(STYLE_POPUP))
    {
        bool lIcons=false;

        double lMaxWidth=0;
        double lY=2;
        for(int i=0;i<mMenu->size();i++)
        {
            PMenuItem lItem=mMenu->Get(i);

            if(lMaxWidth<mItemSize[i].x) lMaxWidth=mItemSize[i].x;
            if(lItem->GetIcon()) lIcons=true;

            mItemPos[i]={0,lY};
            lY+=mItemSize[i].y;
        }

        if(lIcons)
            lMaxWidth+=(int)lIconSize.x;

        if(GetStyle(STYLE_BOTTOMPOS))
        {
            MoveResize(CPoint_d(Position().x,Position().y+Size().y-lY-2),
                        CSize_d(lMaxWidth+12,lY+2));
        }
        else
        {
            Resize(CSize_d(lMaxWidth+12,lY+2));
        }

        mTextX=lIcons?(int)lIconSize.x+10:12;
    }
    else
    {
        double lX=0;
        for(int i=0;i<mMenu->size();i++)
        {
            mItemPos[i]={lX,0};
            lX+=mItemSize[i].x;
        }
    }
}

void CMenuBar::RedrawItem(int)
{
    ///\todo
    Refresh();
//  RefreshRect(mRect);
/*  if(mStyle&STYLE_POPUP)
    {
        RefreshRect(mRect);//CRect_d(0,mItemPos[i].y,mRect.r,
//                  mItemPos[i].y+mItemSize[i].y-1));
    }
    else
    {
        RefreshRect(CRect_d(mItemPos[i],mItemSize[i]));
    }
*/
}

void CMenuBar::SelectItem(int pItem)
{
    mSelected=pItem;

    if(GetStyle(STYLE_POPUP))
    {
        mSelected=-1;
        Refresh(true);
        get_toolkit()->Synchronize();
        sleep(chrono::milliseconds(70));
        mSelected=pItem;
        Refresh(true);
        get_toolkit()->Synchronize();
        sleep(chrono::milliseconds(70));
        mSelected=-1;
        Refresh(true);
        get_toolkit()->Synchronize();
        sleep(chrono::milliseconds(70));
        mSelected=pItem;
        Refresh(true);
        get_toolkit()->Synchronize();
        sleep(chrono::milliseconds(70));
    }

    PMenuItem lItem=mMenu->Get(mSelected);
    lItem->Trigger();

    if(GetStyle(STYLE_POPUP))
    {
        eClosed();
        delete this;
    }
}

void CMenuBar::SelectSubMenu(int i)
{
    ///\todo see how to do this!!
//    if(!HasGrab()&&!GetStyle(STYLE_POPUP))
//    {
//        GrabPointer(GRAB_FAKE);
//    }

    mSelected=i;

    if(mOpenSubMenu>=0)
    {
        if(mSelected==mOpenSubMenu) return;
        mSubMenu->Unmap();
    }

    PMenuItem lItem=mMenu->Get(i);

    mSubMenu=new CMenuBar;
    mSubMenu->SetIconSize(mIconSize);
    mSubMenu->SetStyle(GetStyle());
    mSubMenu->eClosed.Connect(&CMenuBar::OnMenuClosed,this);
///\todo this
/*    if(GetStyle(STYLE_POPUP))
    {
        mSubMenu->CreatePopup(this,lItem->GetSubMenu(),
                TranslateCoords(CPoint_d(mRect.r-2,mItemPos[mSelected].y-2)));
    }
    else
    {
        mSubMenu->CreatePopup(this,lItem->GetSubMenu(),
                TranslateCoords(CPoint_d(mItemPos[mSelected].x-2,mRect.b-2)));
    }
*/
    mSubMenu->Show();
    mOpenSubMenu=mSelected;
}

void CMenuBar::ChangeSelection(int pSelected)
{
    int lSelected=mSelected;
    mSelected=pSelected;

    if(mSelected>=mMenu->size()||mSelected<-1) mSelected=-1;

    if(mSelected<0) mSelected=mOpenSubMenu;

    if(lSelected!=mSelected)
    {
        mTimer->Disable();

        if(mSelected>=0)
        {
            if(mMenu->Get(mSelected)->IsSubMenu()&&(GetStyle(STYLE_POPUP)||mOpenSubMenu>=0))
            {
                mTimer->Enable();
            }
        }

        if(lSelected>=0)
            RedrawItem(lSelected);

        if(mSelected>=0)
            RedrawItem(mSelected);
    }
}

///////////////// events //////////////////

void CMenuBar::OnExpose(const CExposeEvent &pE)
{
    ///\todo see how to do this!!!!
//     if(!HasGrab()&&(GetStyle(STYLE_POPUP)))
//     {
//         GrabPointer(GRAB_POPUP);
//     }

    img::CGC *lGC=pE.mGC;

    get_default_theme()->DrawMenuBar(lGC,this,CTheme::DRAW_NONE);

    for(int i=0;i<mMenu->size();i++)
    {
        if(GetStyle(STYLE_POPUP))
        {
            get_default_theme()->DrawMenuBarItem(lGC,CRect_d(0,mItemPos[i].y,
                Size().x,mItemPos[i].y+mItemSize[i].y-1),this,
                mMenu->Get(i),CTheme::DRAW_NONE);
        }
        else
        {
            get_default_theme()->DrawMenuBarItem(lGC,CRect_d(mItemPos[i].x,mItemPos[i].y,
                    mItemPos[i].x+mItemSize[i].x-1,
                    mItemPos[i].y+mItemSize[i].y-1),this,
                    mMenu->Get(i),CTheme::DRAW_NONE);
        }

    }
}

void CMenuBar::OnButtonDown(const CMouseEvent &pE)
{
    if(pE.mButton==EMouseButton::LEFT)
    {
        mPressed=true;
        if(mSelected>=0)
        {
            RedrawItem(mSelected);
        }
    }
}

void CMenuBar::OnButtonUp(const CMouseEvent &pE)
{
    if(GetStyle(STYLE_POPUP))
    {
        if(pE.mButton!=EMouseButton::LEFT&&pE.mButton!=EMouseButton::RIGHT) return;

        if(mSelected<0) return;

        if(mMenu->Get(mSelected)->IsNormalItem())
        {
            SelectItem(mSelected);
        }
        else if(mMenu->Get(mSelected)->IsSubMenu())
        {
            SelectSubMenu(mSelected);
        }
    }
    else
    {
        if(pE.mButton!=EMouseButton::LEFT) return;

        if(mSelected<0)
        {
            mPressed=false;
            return;
        }

        if(mMenu->Get(mSelected)->IsNormalItem())
        {
            mPressed=false;
            RedrawItem(mSelected);

            SelectItem(mSelected);
        }
        else if(mMenu->Get(mSelected)->IsSubMenu())
        {
            mPressed=false;
            SelectSubMenu(mSelected);
        }
    }
}

void CMenuBar::OnMouseMove(const CMouseEvent &pE)
{
    int lSelected=-1;

    if(GetStyle(STYLE_POPUP))
    {
        for(int i=0;i<mMenu->size();i++)
        {
            if(pE.mPoint.y>=mItemPos[i].y&&
               pE.mPoint.y<=mItemPos[i].y+mItemSize[i].y-1)
            {
                if(mMenu->Get(i)->IsSeparator())
                    break;

                lSelected=i;
                break;
            }
        }
    }
    else
    {
        for(int i=0;i<mMenu->size();i++)
        {
            if(pE.mPoint.x>=mItemPos[i].x&&
               pE.mPoint.x<mItemPos[i].x+mItemSize[i].x&&
               pE.mPoint.y>=mItemPos[i].y&&
               pE.mPoint.y<mItemPos[i].y+mItemSize[i].y)
            {
                lSelected=i;
                break;
            }
        }
    }

    ChangeSelection(lSelected);
}

void CMenuBar::OnMouseOut(const CMouseEvent &pE)
{
    ChangeSelection(mOpenSubMenu);
}

void CMenuBar::OnMenuClosed()
{
    mOpenSubMenu=-1;

    if(!GetStyle(STYLE_POPUP))
    {
//        ReleasePointer();
        ChangeSelection(-1);
    }
    else
    {
        eClosed();
        delete this;
    }
}

void CMenuBar::OnTimer()
{
    mTimer->Disable();
    SelectSubMenu(mSelected);
}

void CMenuBar::OnSize(const CGeometryEvent &pE)
{
    ShapeAll();
    PosAll();
}

/*namespace gui*/ } /*namespace buola*/ }
